// -----------------------------------------------------------------------------
// -- Copyright (c) 2009 Xilinx, Inc.
// -- This design is confidential and proprietary of Xilinx, All Rights
// Reserved.
// -----------------------------------------------------------------------------
// -   ____  ____
// -  /   /\/   /
// - /___/  \  /   Vendor: Xilinx
// - \   \   \/    Version: 1.0
// -  \   \        Filename: BUS_ALIGN_MACHINE.v
// -  /   /        
// - /___/   /\    Date Created: 07/14/2009 
// - \   \  /  \   
// -  \___\/\___\
// - 
// -Revision History:
// -----------------------------------------------------------------------------
/*
--------------------------------------------------------------------------------
Description of module:

The BUS_ALIGN_MACHINE module samples the clock input as if it were a data channel,
and uses the information about the deserialized clock to determine the optimal 
clock/data relationship for that channel.  By dynamically changing the delay of 
the clock channel (with respect to the data bus), the machine places the sampling 
point at the center of the data eye.
--------------------------------------------------------------------------------
*/

`timescale 1ps/1ps
module BUS_ALIGN_MACHINE
	(
	RXCLKDIV,
	RST,
	SAMPLED_CLOCK,
	INC,
	ICE,
	DATA_ALIGNED
	);
	
input		RXCLKDIV;	//PARALLEL RX DOMAIN CLOCK
input		RST;		//RESET SYNCHRONOUS TO Rx DOMAIN
input	[3:0]	SAMPLED_CLOCK;	//4 CLOCK CHANNEL SAMPLES

output		INC;		//COMMAND TO INC/DEC DELAY OF CLOCK CHANNEL
output		ICE;		//COMMAND TO ENABLE DELAY ADJUSTMENT OF CLOCK CHANNEL	
output		DATA_ALIGNED;	//FLAG INDICATING THAT THE BUS IS ALIGNED

reg		INC = 0; 
reg		ICE = 0; 
reg		COUNT = 0; 
reg		UD = 0; 
reg		COUNT_SAMPLE = 0;
reg		UD_SAMPLE = 0;
reg	[3:0] 	CURRENT_STATE = 0;
reg	[3:0]	NEXT_STATE = 0;

wire	[6:0]	COUNT_VALUE; 
wire	[3:0]	SAMPLED_CLOCK_PREV;
wire	[6:0]	COUNT_VALUE_SAMPLE;

count_to_128 machine_counter_total(.clk(RXCLKDIV), .rst(RST), .count(COUNT_SAMPLE), .ud(UD_SAMPLE), .counter_value(COUNT_VALUE_SAMPLE));
count_to_128 machine_counter(.clk(RXCLKDIV), .rst(RST), .count(COUNT), .ud(UD), .counter_value(COUNT_VALUE));

FDR count_reg(.Q(DATA_ALIGNED), .C(RXCLKDIV), .D(DATA_ALIGNEDx), .R(RST));
FDRE bit0(.Q(SAMPLED_CLOCK_PREV[0]), .C(RXCLKDIV), .CE(1'b1), .D(SAMPLED_CLOCK[0]), .R(RST));
FDRE bit1(.Q(SAMPLED_CLOCK_PREV[1]), .C(RXCLKDIV), .CE(1'b1), .D(SAMPLED_CLOCK[1]), .R(RST));
FDRE bit2(.Q(SAMPLED_CLOCK_PREV[2]), .C(RXCLKDIV), .CE(1'b1), .D(SAMPLED_CLOCK[2]), .R(RST));
FDRE bit3(.Q(SAMPLED_CLOCK_PREV[3]), .C(RXCLKDIV), .CE(1'b1), .D(SAMPLED_CLOCK[3]), .R(RST));

assign DATA_ALIGNEDx = ((~CURRENT_STATE[3]) & CURRENT_STATE[2] & CURRENT_STATE[1] & (CURRENT_STATE[0]));

always@(posedge RXCLKDIV or posedge RST)
begin
 if(RST == 1'b1)
  begin
   //Initial Values
   CURRENT_STATE = 4'b0000;
  end
 else
  begin
   //Transition Values
   CURRENT_STATE = NEXT_STATE;
  end
end

//NEXT_STATE LOGIC
always @(CURRENT_STATE or SAMPLED_CLOCK or COUNT_VALUE or SAMPLED_CLOCK_PREV or COUNT_VALUE_SAMPLE)
begin
	case(CURRENT_STATE)
	4'b0000:	NEXT_STATE <= 4'b0001; //RST STATE	
			
	4'b0001:	begin	//INITIAL STATE, SAMPLE TRAINING BIT
			if (SAMPLED_CLOCK_PREV != SAMPLED_CLOCK)
				NEXT_STATE <= 4'b1111;
			else
				NEXT_STATE <= 4'b1000;
			end
			
	4'b1000:	begin	//CHECK SAMPLE TO SEE IF IT IS ON A TRANSITION
			if (SAMPLED_CLOCK_PREV != SAMPLED_CLOCK)
				NEXT_STATE <= 4'b1111;
			else
			if ((COUNT_VALUE > 7'b0001111) && (SAMPLED_CLOCK == 4'b1111))
				NEXT_STATE <= 4'b1011;
			else
			if ((COUNT_VALUE > 7'b0001111) && (SAMPLED_CLOCK == 4'b0000))
				NEXT_STATE <= 4'b0010;
			else
				NEXT_STATE <= 4'b1000;
			end
			
	4'b1111:	begin	//IF SAMPLED POINT IS TRANSITION (INSTABLE), INCREMENT DELAY 3 TIMES
			if (COUNT_VALUE_SAMPLE > 7'b000001)   
				NEXT_STATE <= 4'b1101;
			else
				NEXT_STATE <= 4'b1111;
			end

	4'b1101:	begin	//WAIT 8 CYCLES
			if (COUNT_VALUE > 7'b0000111)
				NEXT_STATE <= 4'b1100;
			else
				NEXT_STATE <= 4'b1101;
			end
	
	4'b1100:	begin	//IDLE (NEEDED FOR COUNTER RESET)
				NEXT_STATE <= 4'b1000;
			end
			
	4'b0010:	begin	//INC ONCE
				NEXT_STATE <= 4'b1110;
			end
			
	4'b1110:	begin	//WAIT 8 CYCLES, LOOK FOR RISING EDGE
			if (COUNT_VALUE_SAMPLE < 7'b0000111)
				NEXT_STATE <= 4'b1110;
			else
			if(SAMPLED_CLOCK != 4'b0000)
				NEXT_STATE <= 4'b0111;
			else
				NEXT_STATE <= 4'b0010;
			end
	
	4'b1011:	begin	//INC ONCE
				NEXT_STATE <= 4'b0100;
			end
			
	4'b0100:	begin	//WAIT 8 CYCLES, LOOK FOR FALLING EDGE
			if (COUNT_VALUE_SAMPLE < 7'b0000111)
				NEXT_STATE <= 4'b0100;
			else
			if(SAMPLED_CLOCK == 4'b0000)
				NEXT_STATE <= 4'b1001;
			else
				NEXT_STATE <= 4'b1011;
			end
			
	4'b1001:	begin	//INC ONCE
				NEXT_STATE <= 4'b0011;
			end
			
	4'b0011:	begin	//WAIT 8 CYCLES, LOOK FOR RISING EDGE
			if (COUNT_VALUE_SAMPLE < 7'b0000111)
				NEXT_STATE <= 4'b0011;
			else
			if(SAMPLED_CLOCK != 4'b0000)
				NEXT_STATE <= 4'b0111;
			else
				NEXT_STATE <= 4'b1001;
			end
	
	4'b0111:	NEXT_STATE <= 4'b0111;  //TRAINING COMPLETE FOR THIS CHANNEL			
    	
    	default:	NEXT_STATE <= 4'b0000;
	endcase
end

//OUTPUT LOGIC

always @(CURRENT_STATE)
begin
	case(CURRENT_STATE)
	4'b0000:	begin	//RST STATE
			INC = 1'b0;
  			ICE = 1'b0;
			COUNT = 1'b0;
			UD = 1'b0;			
			COUNT_SAMPLE = 1'b0;
			UD_SAMPLE = 1'b0;
			end
	
	4'b0001:	begin	//INITIAL STATE, SAMPLE TRAINING BIT
			INC = 1'b0;
  			ICE = 1'b0;
			COUNT = 1'b0;
			UD = 1'b0;			
			COUNT_SAMPLE = 1'b0;
			UD_SAMPLE = 1'b0;
			end
			
	4'b1000:	begin	//CHECK SAMPLE TO SEE IF IT IS ON A TRANSITION
			INC = 1'b0;
  			ICE = 1'b0;
			COUNT = 1'b1;
			UD = 1'b1;			
			COUNT_SAMPLE = 1'b0;
			UD_SAMPLE = 1'b0;
			end
			
	4'b1111:	begin	//IF SAMPLED POINT IS TRANSITION, INCREMENT DELAY 2 TIMES
			INC = 1'b1;
  			ICE = 1'b1;
			COUNT = 1'b0;
			UD = 1'b0;			
			COUNT_SAMPLE = 1'b1; 
			UD_SAMPLE = 1'b1;
			end
	
	4'b1101:	begin	//WAIT 8 CYCLES
			INC = 1'b0;
  			ICE = 1'b0;
			COUNT = 1'b1;
			UD = 1'b1;			
			COUNT_SAMPLE = 1'b0;
			UD_SAMPLE = 1'b0;
			end
			
	4'b1100:	begin	//IDLE (NEEDED FOR COUNTER RESET)
			INC = 1'b0;
  			ICE = 1'b0;
			COUNT = 1'b0;
			UD = 1'b0;			
			COUNT_SAMPLE = 1'b0;
			UD_SAMPLE = 1'b0;
			end
	
	4'b0010:	begin	//INC ONCE
			INC = 1'b1;
  			ICE = 1'b1;
			COUNT = 1'b0;
			UD = 1'b0;			
			COUNT_SAMPLE = 1'b0;
			UD_SAMPLE = 1'b0;
			end
	
	4'b1110:	begin	//WAIT 8 CYCLES, LOOK FOR 1 (TO LOCATE FALLING EDGE)
			INC = 1'b0;
  			ICE = 1'b0;
			COUNT = 1'b0;
			UD = 1'b0;			
			COUNT_SAMPLE = 1'b1;
			UD_SAMPLE = 1'b1;
			end
			
	4'b1011:	begin	//INC ONCE
			INC = 1'b1;
  			ICE = 1'b1;
			COUNT = 1'b0;
			UD = 1'b0;			
			COUNT_SAMPLE = 1'b0;
			UD_SAMPLE = 1'b0;
			end
	
	4'b0100:	begin	//WAIT 8 CYCLES, LOOK FOR 0
			INC = 1'b0;
  			ICE = 1'b0;
			COUNT = 1'b0;
			UD = 1'b0;			
			COUNT_SAMPLE = 1'b1;
			UD_SAMPLE = 1'b1;
			end
	
	4'b1001:	begin	//INC ONCE
			INC = 1'b1;
  			ICE = 1'b1;
			COUNT = 1'b0;
			UD = 1'b0;			
			COUNT_SAMPLE = 1'b0;
			UD_SAMPLE = 1'b0;
			end
	
	4'b0011:	begin	//WAIT 8 CYCLES, LOOK FOR 1 (TO LOCATE FALLING EDGE)
			INC = 1'b0;
  			ICE = 1'b0;
			COUNT = 1'b0;
			UD = 1'b0;			
			COUNT_SAMPLE = 1'b1;
			UD_SAMPLE = 1'b1;
			end		
			
	4'b0111:	begin	//TRAINING COMPLETE ON THIS CHANNEL
			INC = 1'b0;
  			ICE = 1'b0;
			COUNT = 1'b0;
			UD = 1'b0;			
			COUNT_SAMPLE = 1'b0;
			UD_SAMPLE = 1'b0;
			end
			
	default:	begin	
			INC = 1'b0;
  			ICE = 1'b0;
			COUNT = 1'b0;
			UD = 1'b0;			
			COUNT_SAMPLE = 1'b0;
			UD_SAMPLE = 1'b0;
			end
	endcase
end

endmodule

`timescale  1ps/1ps
module count_to_128(clk, rst, count, ud, counter_value);

//This module counts up/down between 0 to 128

input clk, rst, count, ud;
output [6:0] counter_value;

wire [6:0] counter_value_preserver;
reg [6:0] counter_value/*synthesis syn_noprune = 1*/;

always@(posedge clk or posedge rst)
begin
if(rst == 1'b1)
 counter_value = 7'h00;
else
 begin
  case({count,ud})
   2'b00: counter_value = 7'h00;
   2'b01: counter_value = counter_value_preserver;
   2'b10: counter_value = counter_value_preserver - 1'b1;
   2'b11: counter_value = counter_value_preserver + 1'b1;
   default: counter_value = 7'h00;
  endcase
 end
end

assign counter_value_preserver = counter_value;

endmodule

	
